﻿namespace EasyToolkit.Tools.Reflection
{
    using System;
    using System.Linq;
    using System.Reflection;
    using EasyToolkit.Tools.Extensions;

    /// <summary> Internal use</summary>
    public static class TypeHelpers
    {
        public static Type GetType(string assemblyName, string typeName)
        {
            Type ret = null;
            try
            {
                assemblyName = assemblyName.EmptyIfNull().Trim();
                typeName = typeName.EmptyIfNull().Trim();

                if (string.IsNullOrEmpty(typeName))
                    throw new EasyToolkitException("'typeName' cannot be null or empty");
                    
                Assembly assembly;
                if (string.IsNullOrEmpty(assemblyName))
                    assembly = Assembly.GetCallingAssembly();
                else
                    assembly = Assembly.Load(assemblyName.Trim());

                ret = GetTypeInternal(assembly, typeName); 
            }
            catch (Exception ex)
            {
                throw new EasyToolkitException(string.Format("Cannot retrieve type '{0}.{1}': {2}",
                                               assemblyName, typeName, ex.Message), ex);
            }
            return ret;
        }

        public static Type GetType(string assemblyName, string typeName, string methodName)
        {
            Type ret = null;
            try
            {
                Assembly assembly;
                assemblyName = assemblyName.EmptyIfNull().Trim();
                typeName = typeName.EmptyIfNull().Trim();
                methodName = methodName.EmptyIfNull().Trim();

                if (string.IsNullOrEmpty(typeName))
                    throw new EasyToolkitException("'typeName' cannot be null or empty");

                if (string.IsNullOrEmpty(assemblyName))
                    assembly = Assembly.GetCallingAssembly();
                else
                    assembly = Assembly.Load(assemblyName.Trim());

                ret = GetTypeInternal(assembly, typeName);
                if (!string.IsNullOrEmpty(methodName))
                {
                    MethodInfo method = ret.GetMethod(methodName);
                    if (method != null)
                        throw new EasyToolkitException("Cannot find the requested method");
                    ret = method.ReturnType;
                }
                if (ret == null || ret.Equals(typeof(void)))
                    throw new EasyToolkitException("Cannot find the requested type");
            }
            catch (Exception ex)
            {
                throw new EasyToolkitException(string.Format("Cannot retrieve type for '{0}.{1}' method '{2}': {3}",
                                               assemblyName, typeName, methodName, ex.Message), ex);
            }
            return ret;
        }

        static private Type GetTypeInternal(Assembly assembly, string typeName)
        {
            Type ret = null;
            if (assembly != null && !string.IsNullOrEmpty(typeName))
            {
                foreach (Type type in assembly.GetTypes())
                {
                    if (typeName.Equals(type.FullName) || typeName.Equals(type.Name))
                    {
                        ret = type;
                        break;
                    }
                }
            }
            if(ret == null)
                throw new EasyToolkitException("Cannot find the requested type");
            return ret;
        }
    }
}
